package cgs

import (
	"errors"
	"cgs-server/server"
	"cgs-server/server/base"
	"cgs-server/server/model"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"time"
)

type CgsRepository interface {
	base.Repository
	Add(model *CgsAddModel) (*mongo.InsertOneResult, error)
	FindByProjectId(id primitive.ObjectID) (*CgsProj, error)

	GetVisualByPublishId(publishId, collectionName string) (*model.Visual, error)
}

func NewCgsRepository() CgsRepository {
	return &cgsRepository{
		base.RepositoryStruct{
			CollectionName: server.CgsProjectCollectionName,
		},
	}
}

type cgsRepository struct {
	base.RepositoryStruct
}

func (c *cgsRepository) Add(model *CgsAddModel) (*mongo.InsertOneResult, error) {
	if c.Mongo == nil {
		return nil, errors.New("db is not created")
	}

	now := time.Now()
	doc := bson.M{
		"ID":         model.IDObjId,
		"Name":       model.Name,
		"Data":       model.Data,
		"JsPath":     model.FilePath,
		"FilePath":   model.FilePath,
		"CreateTime": now,
		"UpdateTime": now,
		"IsPublic":   model.Public,
		"PublishId": model.PublishId,
		"UserID": model.UserId,
	}
	return c.Mongo.InsertOne(c.CollectionName, doc)
}


func (c *cgsRepository) FindByProjectId(id primitive.ObjectID) (*CgsProj, error) {
	db, err := server.Mongo()
	if err != nil {
		return nil, err
	}
	filter := bson.M{
		"ID": id,
	}
	var result CgsProj
	_, err = db.FindOne(server.CgsProjectCollectionName, filter, &result)
	return &result, err
}

func (c *cgsRepository) Insert(mdl *model.DataUserModel) error {
	if cgsProj, ok := mdl.Data.(*CgsProj); ok {
		if err := c.CheckDB(); err != nil {
			return err
		}
		cgsProj.ResolveEntity(cgsProj, mdl.User)
		_, err := c.Mongo.InsertOne(c.CollectionName, cgsProj)
		return err
	} else {
		return errors.New("CgsProj type error")
	}
}

func (c *cgsRepository) Update(mdl *model.DataUserModel) error {
	if cgsProj, ok := mdl.Data.(*CgsProj); ok {
		if err := c.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"ID": cgsProj.ID,
		}
		cgsProj.ResolveFilter(cgsProj, mdl.User, &filter)
		set := bson.M{}
		if cgsProj.Name != "" {
			set["Name"] = cgsProj.Name
		}
		if cgsProj.Data != "" {
			set["Data"] = cgsProj.Data
		}
		if cgsProj.JsPath != "" {
			set["JsPath"] = cgsProj.JsPath
		}
		if cgsProj.FilePath != "" {
			set["FilePath"] = cgsProj.FilePath
		}
		if cgsProj.PublishId != "" {
			set["PublishId"] = cgsProj.PublishId
		}
		if cgsProj.SceneId != "" {
			set["sceneId"] = cgsProj.SceneId
		}
		if cgsProj.Public != nil {
			set["Public"] = cgsProj.Public
		}
		cgsProj.ResolveUpdateCondition(cgsProj, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		_, err := c.Mongo.UpdateOne(c.CollectionName, filter, update)
		return err
	} else {
		return errors.New("CgsProj type error")
	}
}

func (c *cgsRepository) Delete(mdl *model.DataUserModel) error {
	if cgsProj, ok := mdl.Data.(*CgsProj); ok {
		if err := c.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"ID": cgsProj.ID,
		}
		cgsProj.ResolveFilter(cgsProj, mdl.User, &filter)
		_, err := c.Mongo.DeleteOne(c.CollectionName, filter)
		return err
	} else {
		return errors.New("CgsProj type error")
	}
}

func (c *cgsRepository) Find(mdl *model.DataUserModel) (interface{}, error) {
	if cgsProj, ok := mdl.Data.(*CgsProj); ok {
		if err := c.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		cgsProj.ResolveFilter(cgsProj, mdl.User, &filter)
		opts := options.FindOptions{}
		if mdl.Options != nil {
			opts = *mdl.Options
		}
		results := []*CgsProj{}
		err := c.Mongo.FindMany(c.CollectionName, filter, &results, &opts)
		return results, err
	} else {
		return nil, errors.New("CgsProj type error")
	}
}

func (c *cgsRepository) FindOne(mdl *model.DataUserModel) (interface{}, error) {
	if cgsProj, ok := mdl.Data.(*CgsProj); ok {
		if err := c.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{
			"ID": cgsProj.ID,
		}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		cgsProj.ResolveFilter(cgsProj, mdl.User, &filter)
		result := &CgsProj{}
		find, err := c.Mongo.FindOne(c.CollectionName, filter, result)
		if find {
			return result, nil
		}
		return nil, err
	} else {
		return nil, errors.New("CgsProj type error")
	}
}

func (c *cgsRepository) GetVisualByPublishId(publishId, collectionName string) (*model.Visual, error) {
	if err := c.InitDB(); err != nil {
		return &model.Visual{}, err
	}
	bsonId, err := primitive.ObjectIDFromHex(publishId)
	if err != nil {
		return nil, err
	}
	filter := bson.M{
		"ID": bsonId,
	}
	result := &model.Visual{}
	find, err := c.Mongo.FindOne(collectionName, filter, result)
	if !find {
		return nil, nil
	}
	return result, err
}
